using System;
using System.Collections.Generic;

namespace OpenRay
{
	//Immutable class
	public class PrimitiveHit : IComparable
	{
		private readonly GeometryHit geomHit;
		private readonly IList<Light> lights;  //Should be IList
		private readonly Matrix worldToModel;
		private readonly bool localViewer;
		private readonly uint depth;
		
		public float Distance {
			get {
				return geomHit.Distance;	
			}
		}
		
		public PrimitiveHit ( GeometryHit h, IList<Light> lts, Matrix w2m, bool lv, uint d )
		{
			geomHit = h;
			lights = lts;
			worldToModel = w2m;
			localViewer = lv;
			depth = d;
		}
		
		public int CompareTo(Object obj)
		{
			if ( obj == null )
				return -1;
			
			PrimitiveHit temp = obj as PrimitiveHit;
			if (temp != null )
				return geomHit.CompareTo( temp.geomHit );
			else
				throw new ArgumentException( "Object is not a PrimitiveHit" );
		}
		
		public Color Shade (Ray worldRay) 
		{
			Point worldHit = worldRay.Origin + worldRay.Direction * geomHit.Distance;
			Point modelHit = geomHit.ModelHit();
			
			Vector modelNormal = geomHit.Normal(modelHit);
			Vector worldNormal = Matrix.TransposedMultiply(worldToModel, modelNormal);
				
			Material material = geomHit.Material(modelHit);
			
			//Lighting Coordinates MUST be provided in world space.
			Vector viewer = (localViewer) ? Vector.Normalize( worldRay.Direction ) : new Vector( 0, 0, 1 );
			
			return material.Shade(worldHit, modelHit, viewer, worldNormal, lights, depth );
		}
	}
}

